package com.huaguoguo.cyg.service.seckill;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import com.huaguoguo.cyg.entity.seckill.dto.RedPacketRecord;
import com.huaguoguo.cyg.exceptions.SecKillException;
import com.huaguoguo.cyg.seckill.distributedlock.redis.RedissLockUtil;
import com.huaguoguo.cyg.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class RedPacketService {

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 初始化红包数据 <br>
     * 抢红包之前，先把红包拆成指定的份数
     *
     * @param num        红包的个数
     * @param totalMoney 红包的总金额 单位：分
     * @return 拆分的红包
     */
    public List<Integer> splitRedPack(Integer num, Integer totalMoney) {
        List<Integer> redPackList = CollUtil.list(false);
        // 剩余金额
        Integer restMoney = totalMoney;
        // 随机分配红包
        for (int i = 0; i < num; i++) {
            int singleMoney = 0;
            // 最后一次循环，最后一份红包=现有余额
            if (i == (num - 1)) {
                singleMoney = restMoney;
            } else {
                singleMoney = RandomUtil.getRandom().nextInt((int) (restMoney / (num - i) * 2 - 1)) + 1;
            }
            redPackList.add(singleMoney);
            restMoney -= singleMoney;
        }
        int sum = redPackList.stream().mapToInt(Integer::intValue).sum();
        if (sum != totalMoney) {
            throw new SecKillException("拆分红包异常！！！");
        }
        return redPackList;
    }

    /**
     * 抢红包业务实现
     *
     * @param redPacketId
     * @param userId
     * @return 想到的钱
     */
    @Transactional
    public Integer startSeckil(long redPacketId, int userId) {
        Integer money = 0;
        boolean res = false;
        try {
            /**
             * 获取锁
             */
            res = RedissLockUtil.tryLock(redPacketId + "", TimeUnit.SECONDS, 3, 10);
            if (res) {
                long restPeople = redisUtil.decr(redPacketId + "-restPeople", 1);
                /**
                 * 如果是最后一人
                 */
                if (restPeople == 1) {
                    money = Integer.parseInt(redisUtil.getValue(redPacketId + "-money").toString());
                } else {
                    Integer restMoney = Integer.parseInt(redisUtil.getValue(redPacketId + "-money").toString());
                    Random random = new Random();
                    //随机范围：[1,剩余人均金额的两倍]
                    money = random.nextInt((int) (restMoney / (restPeople + 1) * 2 - 1)) + 1;
                }
                redisUtil.decr(redPacketId + "-money", money);
                /**
                 * 异步入库
                 */
                RedPacketRecord record = new RedPacketRecord();
                record.setMoney(money);
                record.setRedPacketId(redPacketId);
                record.setUid(userId);
                record.setCreateTime(new Timestamp(System.currentTimeMillis()));
                saveRecord(record);
                /**
                 * 异步入账
                 */
            } else {
                /**
                 * 获取锁失败相当于抢红包失败，红包个数加一
                 */
                redisUtil.incr(redPacketId + "-num", 1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (res) {//释放锁
                RedissLockUtil.unlock(redPacketId + "");
            }
        }
        return money;
    }

    /**
     * 微信抢红包业务实现
     *
     * @param redPacketId
     * @param userId
     * @return 抢到第几份红包
     */
    @Transactional
    public long startTwoSeckil(long redPacketId, String userId) {
        // 红包编号
        long redPackNo = 0L;
        boolean res = false;
        try {
            /**
             * 获取锁 保证红包数量和计算红包金额的原子性操作
             */
            res = RedissLockUtil.tryLock(redPacketId + "", TimeUnit.SECONDS, 3, 10);
            if (res) {
                // 取红包编号
                redPackNo = redisUtil.decr(redPacketId + "-num", 1);
                if (redPackNo < 0) {
                    throw new SecKillException("手慢了，红包派完了");
                }
            } else {
                /**
                 * 获取锁失败相当于抢红包失败
                 */
                throw new SecKillException("手慢了，红包派完了");
            }
        } finally {
            if (res) {//释放锁
                RedissLockUtil.unlock(redPacketId + "");
            }
        }
        return redPackNo;
    }

    @Async
    void saveRecord(RedPacketRecord record) {

    }
}
